﻿/**
*    @file:    filestorageclient.cpp
*    @brief:
*    @author:  sanshi522@163.com
*    @date:    2025-05-27  10:14
*/
#include "qfilestorageclient.h"
#include <QDebug>
#include <QEventLoop>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QUrlQuery>

QFileStorageClient::QFileStorageClient(QObject *parent)
    : QObject(parent)
{
}

QFileStorageClient::~QFileStorageClient()
{
}

void QFileStorageClient::setServiceAddress(QString url)
{
    serviceAddress = url;
}

bool QFileStorageClient::pushFile(const QString &localPath, const QString &remotePath)
{
    QFile file(localPath);
    if (!file.exists())
    {
        lastErrorText = "本地文件不存在：";
        qDebug() << "本地文件不存在：" << localPath;
        return false;
    }

    if (!file.open(QIODevice::ReadOnly))
    {
        lastErrorText = "无法打开本地文件：";
        qDebug() << "无法打开本地文件：" << localPath;
        return false;
    }

    QNetworkAccessManager manager;
    manager.setNetworkAccessible(QNetworkAccessManager::Accessible);
    const qint64 chunkSize = 10 * 1024 * 1024; // 10 MB per chunk
    qint64 offset = 0;

    while (!file.atEnd())
    {
        file.seek(offset);
        QByteArray chunkData = file.read(chunkSize);
        QString base64Data = QString::fromUtf8(chunkData.toBase64());

        // 构建 JSON 请求体
        QJsonObject jsonObj;
        jsonObj["path"] = remotePath;
        jsonObj["offset"] = offset;
        jsonObj["data"] = base64Data;
        jsonObj["length"] = chunkData.size();

        QJsonDocument jsonDoc(jsonObj);
        QByteArray postData = jsonDoc.toJson();

        QUrl url(serviceAddress + "/write"); // 修改为你的服务端地址
        QNetworkRequest request(url);
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

        QNetworkReply *reply = manager.post(request, postData);

        QEventLoop loop;
        QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
        loop.exec(); // 同步等待响应

        if (reply->error() != QNetworkReply::NoError)
        {
            lastErrorText = "网络错误：";
            qDebug() << "网络错误：" << reply->errorString();
            reply->deleteLater();
            file.close();
            return false;
        }

        QByteArray responseData = reply->readAll();
        QJsonParseError parseError;
        QJsonDocument responseDoc = QJsonDocument::fromJson(responseData, &parseError);

        if (parseError.error != QJsonParseError::NoError || !responseDoc.isObject())
        {
            lastErrorText = "无法解析服务器响应：";
            qDebug() << "无法解析服务器响应：" << responseData;
            reply->deleteLater();
            file.close();
            return false;
        }

        QJsonObject resObj = responseDoc.object();
        int status = resObj.value("status").toInt();
        if (status != 0)
        {
            lastErrorText = "服务器返回错误：";
            qDebug() << "服务器返回错误：" << resObj.value("statusText").toString();
            reply->deleteLater();
            file.close();
            return false;
        }
        offset = resObj.value("size").toVariant().toULongLong();
        qDebug() << "已写入" << chunkData.size() << "字节，偏移量：" << offset;
        reply->deleteLater();
    }

    file.close();
    return true;
}

bool QFileStorageClient::pullFile(const QString &localPath, const QString &remotePath)
{
    QFile file(localPath);
    if (file.exists())
    {
        // 如果文件已存在，删除或清空它
        file.remove(); // 或者你可以选择追加写入
    }

    if (!file.open(QIODevice::WriteOnly))
    {
        lastErrorText = "无法创建本地文件：";
        qDebug() << "无法创建本地文件：" << localPath;
        return false;
    }

    QNetworkAccessManager manager;
    manager.setNetworkAccessible(QNetworkAccessManager::Accessible);
    const qint64 chunkSize = 10 * 1024 * 1024; // 每次读取 10MB
    qint64 offset = 0;

    while (true)
    {
        // 构造请求体
        QJsonObject jsonObj;
        jsonObj["path"] = remotePath;
        jsonObj["offset"] = offset;
        jsonObj["length"] = chunkSize;

        QJsonDocument jsonDoc(jsonObj);
        QByteArray postData = jsonDoc.toJson();

        QUrl url(serviceAddress + "/read"); // 替换为你的服务端地址
        QNetworkRequest request(url);
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

        QNetworkReply *reply = manager.post(request, postData);

        QEventLoop loop;
        QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
        loop.exec(); // 等待响应

        if (reply->error() != QNetworkReply::NoError)
        {
            lastErrorText = "网络错误：";
            qDebug() << "网络错误：" << reply->errorString();
            reply->deleteLater();
            file.close();
            return false;
        }

        QByteArray responseData = reply->readAll();
        QJsonParseError parseError;
        QJsonDocument responseDoc = QJsonDocument::fromJson(responseData, &parseError);

        if (parseError.error != QJsonParseError::NoError || !responseDoc.isObject())
        {
            lastErrorText = "无法解析服务器响应：";
            qDebug() << "无法解析服务器响应：" << responseData;
            reply->deleteLater();
            file.close();
            return false;
        }

        QJsonObject resObj = responseDoc.object();
        int status = resObj.value("status").toInt();
        if (status != 0)
        {
            lastErrorText = "服务器返回错误：";
            qDebug() << "服务器返回错误：" << resObj.value("statusText").toString();
            reply->deleteLater();
            file.close();
            return false;
        }

        QString base64Data = resObj.value("data").toString();
        QByteArray decodedData = QByteArray::fromBase64(base64Data.toUtf8());

        if (decodedData.isEmpty())
        {
            qDebug() << "接收到空数据，可能是文件已读完。";
            break;
        }

        // 写入本地文件
        qint64 bytesWritten = file.write(decodedData);
        if (bytesWritten != decodedData.size())
        {
            lastErrorText = "写入文件失败";
            qDebug() << "写入文件失败，只写了" << bytesWritten << "字节，预期" << decodedData.size();
            reply->deleteLater();
            file.close();
            return false;
        }

        offset += decodedData.size();
        qDebug() << "已接收并写入" << decodedData.size() << "字节，偏移量：" << offset;

        reply->deleteLater();

        // 如果收到的数据小于 chunkSize，说明已经读取完成
        if (decodedData.size() < chunkSize)
        {
            break;
        }
    }

    file.close();
    qDebug() << "文件下载完成，总大小：" << offset << "字节，保存路径：" << localPath;
    return true;
}

bool QFileStorageClient::pushData(const QByteArray &localData, const QString &remotePath)
{
    if (localData.isEmpty())
    {
        lastErrorText = "数据为空，无法上传";
        qDebug() << "数据为空，无法上传";
        return false;
    }

    QNetworkAccessManager manager;
    manager.setNetworkAccessible(QNetworkAccessManager::Accessible);
    const qint64 chunkSize = 10 * 1024 * 1024; // 10 MB per chunk
    qint64 offset = 0;

    while (offset < localData.size())
    {
        qint64 bytesToRead = qMin(chunkSize, static_cast<qint64>(localData.size()) - offset);
        QByteArray chunk = localData.mid(offset, bytesToRead);
        QString base64Data = QString::fromUtf8(chunk.toBase64());

        // 构造 JSON 请求体
        QJsonObject jsonObj;
        jsonObj["path"] = remotePath;
        jsonObj["offset"] = offset;
        jsonObj["data"] = base64Data;
        jsonObj["length"] = chunk.size();

        QJsonDocument jsonDoc(jsonObj);
        QByteArray postData = jsonDoc.toJson();

        QUrl url(serviceAddress + "/write"); // 替换为你的服务端地址
        QNetworkRequest request(url);
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

        QNetworkReply *reply = manager.post(request, postData);

        QEventLoop loop;
        QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
        loop.exec(); // 同步等待响应

        if (reply->error() != QNetworkReply::NoError)
        {
            lastErrorText = "网络错误：";
            qDebug() << "网络错误：" << reply->errorString();
            reply->deleteLater();
            return false;
        }

        QByteArray responseData = reply->readAll();
        QJsonParseError parseError;
        QJsonDocument responseDoc = QJsonDocument::fromJson(responseData, &parseError);

        if (parseError.error != QJsonParseError::NoError || !responseDoc.isObject())
        {
            lastErrorText = "无法解析服务器响应：";
            qDebug() << "无法解析服务器响应：" << responseData;
            reply->deleteLater();
            return false;
        }

        QJsonObject resObj = responseDoc.object();
        int status = resObj.value("status").toInt();
        if (status != 0)
        {
            lastErrorText = "服务器返回错误：";
            qDebug() << "服务器返回错误：" << resObj.value("statusText").toString();
            reply->deleteLater();
            return false;
        }

        offset += chunk.size();
        qDebug() << "已写入" << chunk.size() << "字节，偏移量：" << offset;

        reply->deleteLater();
    }

    return true;
}

bool QFileStorageClient::pullData(QByteArray &localData, const QString &remotePath)
{
    localData.clear();

    QNetworkAccessManager manager;
    manager.setNetworkAccessible(QNetworkAccessManager::Accessible);
    const qint64 chunkSize = 10 * 1024 * 1024; // 10 MB per chunk
    qint64 offset = 0;

    while (true)
    {
        // 构造请求体
        QJsonObject jsonObj;
        jsonObj["path"] = remotePath;
        jsonObj["offset"] = offset;
        jsonObj["length"] = chunkSize;

        QJsonDocument jsonDoc(jsonObj);
        QByteArray postData = jsonDoc.toJson();

        QUrl url(serviceAddress + "/read"); // 替换为你的服务端地址
        QNetworkRequest request(url);
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
        QNetworkReply *reply = manager.post(request, postData);

        QEventLoop loop;
        QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
        loop.exec(); // 等待响应

        if (reply->error() != QNetworkReply::NoError)
        {
            lastErrorText = QString("网络错误! Code:%1 Text:%2").arg(reply->error()).arg(reply->errorString());
            qDebug() << lastErrorText;
            reply->deleteLater();
            return false;
        }

        QByteArray responseData = reply->readAll();
        QJsonParseError parseError;
        QJsonDocument responseDoc = QJsonDocument::fromJson(responseData, &parseError);

        if (parseError.error != QJsonParseError::NoError || !responseDoc.isObject())
        {
            lastErrorText = QString("无法解析服务器响应：%1").arg(QString::fromUtf8(responseData));
            qDebug() << lastErrorText;
            reply->deleteLater();
            return false;
        }

        QJsonObject resObj = responseDoc.object();
        int status = resObj.value("status").toInt();
        if (status != 0)
        {
            lastErrorText = QString("服务器返回错误：%1").arg(resObj.value("statusText").toString());
            qDebug() << lastErrorText;
            reply->deleteLater();
            return false;
        }

        QString base64Data = resObj.value("data").toString();
        QByteArray decodedData = QByteArray::fromBase64(base64Data.toUtf8());

        if (decodedData.isEmpty())
        {
            lastErrorText = "接收到空数据，可能是文件已读完。";
            qDebug() << "接收到空数据，可能是文件已读完。";
            break;
        }

        localData.append(decodedData);
        offset += decodedData.size();
        //        qDebug() << "已接收并缓存" << decodedData.size() << "字节，总大小：" << localData.size();

        reply->deleteLater();

        if (decodedData.size() < chunkSize)
        {
            break;
        }
    }

    //    qDebug() << "数据下载完成，总大小：" << localData.size() << "字节";
    return true;
}

bool QFileStorageClient::getFileInfo(const QString &remotePath, RemoteFileInfo &info)
{
    // 创建网络访问管理器
    QNetworkAccessManager manager;
    manager.setNetworkAccessible(QNetworkAccessManager::Accessible);

    // // 连接请求完成信号到处理函数
    // QObject::connect(manager, &QNetworkAccessManager::finished,
    //                  &a, &handleReply);

    // 创建URL并设置查询参数
    QUrl url(serviceAddress + "/info");
    QUrlQuery query;

    // 添加查询参数如 (?name=Qt&version=6.5&feature=network)
    query.addQueryItem("path", remotePath);

    // 将查询参数添加到URL
    url.setQuery(query);
    //qDebug() << "请求URL: " << url.toString();

    // 创建请求对象
    QNetworkRequest request(url);

    // 设置请求头（可选）
    request.setHeader(QNetworkRequest::UserAgentHeader, "MyQtClient/2.0");

    // 发送GET请求
    QNetworkReply *reply = manager.get(request);

    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec(); // 等待响应

    // if (reply->error() != QNetworkReply::NoError) {
    //     lastErrorText = "网络错误：";
    //     qDebug() << "网络错误：" << reply->errorString();
    //     reply->deleteLater();
    //     return false;
    // }

    QByteArray responseData = reply->readAll();
    QJsonParseError parseError;
    QJsonDocument responseDoc = QJsonDocument::fromJson(responseData, &parseError);

    //parseError.error != QJsonParseError::NoError ||
    if (!responseDoc.isObject())
    {
        lastErrorText = "无法解析服务器响应：";
        qDebug() << "无法解析服务器响应：" << responseData;
        reply->deleteLater();
        return false;
    }

    QJsonObject resObj = responseDoc.object();
    info.state = resObj.value("status").toInt();
    if (info.state == 0)
    {
        info.isDir = resObj.value("isDir").toBool();
        info.fileSize = resObj.value("size").toInt();
    }

    reply->deleteLater();

    return true;
}

QString QFileStorageClient::getLastErrorText() const
{
    return lastErrorText;
}

int QFileStorageClient::getLastErrorCode() const
{
    return lastErrorCode;
}
